package database;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.io.*;

public class DataFile implements Serializable {

	private String fileName;
	private Map<String, Integer> descriptor;
	private Map<Integer, Map<String, String>> records = new HashMap<Integer, Map<String, String>>();
	private ArrayList<String> indexNames = new ArrayList<String>();
	private int pointer1 = -1;
	private int pointer2 = -1;
	private  Map<String, Index> indexFiles = new HashMap<String, Index>();

	public DataFile(String fileName, Map<String, Integer> descriptor)
			throws IllegalArgumentException {
		File f = new File(fileName);
		try {
			f.createNewFile();
			FileOutputStream fos = new FileOutputStream(f);
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			oos.writeObject(this);
			this.setFileName(fileName);
			this.setDescriptor(descriptor);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public DataFile() {
		
	}

	public Index createIndex(String indexName, String column)
			throws IllegalArgumentException {
		HashMap<String, String> result = new HashMap<String, String>();
		if (indexNames.contains(indexName)) {
			throw new IllegalArgumentException();
		}
		indexNames.add(indexName);
		for (Map.Entry<Integer, Map<String, String>> em : records.entrySet()) {
			String value = em.getValue().get(column);
			String recordId = em.getKey().toString();
			result.put(value, recordId);
		}

		Index index = new Index(indexName, result);
		indexFiles.put(indexName,index);
		return index;
	}

	public Map<String, String> getRecord(int recordId) {
		for (Map.Entry<Integer, Map<String, String>> item : records.entrySet()) {
			if (item.getKey() == recordId) {
				return item.getValue();
			}
		}
		return null;
	}

	public int insertRecord(Map<String, String> record)
			throws IllegalArgumentException {
		Boolean flag1 = false;
		Boolean flag2 = false;
		int id = records.size();
		for (Map.Entry<String, String> item : record.entrySet()) {
			if (!descriptor.containsKey(item.getKey())) {
				flag1 = true;
			} else if(item.getValue().length() > descriptor.get(item.getKey())) {
				flag2 = true;
		    }
		}

		if (flag1||flag2) {
			throw new IllegalArgumentException();
		}
		records.put(id, record);
		return id;
	}

	public void dumpFile() {
		try {
			FileOutputStream fos = new FileOutputStream(this.fileName);
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			oos.writeObject(this);
			oos.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public String viewFile() {
		String result1 = "";
		String result = "";
		for (Map.Entry<Integer, Map<String, String>> em : records.entrySet()) {
			result1 = em.getKey() + ": \n";
			String result2 = "";
			for (Map.Entry<String, String> m : em.getValue().entrySet()) {
				if (m.getValue() != null) {
					result2 += "    " + m.getKey() + ": " + m.getValue()
							+ "\n";
				}
			}
			result = result + result1 + result2;
		}
		System.out.println(result);
		return result;
	}

	public void dropFile() {
		File f = new File(fileName);
		f.delete();
		records.clear();
		indexFiles.clear();
		DataManager.fileInMemory.remove(fileName);
		for (int i = 0; i < indexNames.size(); i++) {
			dropIndex(indexNames.get(i));
		}
	}

	public Index restoreIndex(String indexName) throws IllegalArgumentException {
		if (indexNames.contains(indexName)) {
			throw new IllegalArgumentException();
		}
		try {
			FileInputStream fis = new FileInputStream(indexName);
			ObjectInputStream ois = new ObjectInputStream(fis);
			Index restoredIndex = (Index) ois.readObject();
			return restoredIndex;
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			throw new IllegalArgumentException();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;
	}

	public void dropIndex(String indexName) {
		File f = new File(indexName);
		f.delete();
		indexFiles.remove(indexName);
		indexNames.remove(indexName);
	}

	public Iterator<Integer> iterator() {

		return new FileIterator();
	}

	private class FileIterator implements Iterator<Integer> {

		@Override
		public boolean hasNext() {
			// TODO Auto-generated method stub
			int tmp = pointer1;
			tmp++;
			if (tmp < records.size()) {
				return true;
			} else {
				pointer1 = -1;
				return false;
			}
		}

		@Override
		public Integer next() {
			// TODO Auto-generated method stub
			pointer1++;
			return pointer1;
		}

		@Override
		public void remove() {
			// TODO Auto-generated method stub
			pointer2++;
			records.remove(pointer1 + pointer2);
			pointer1--;
		}

	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public Map<String, Integer> getDescriptor() {
		return descriptor;
	}

	public void setDescriptor(Map<String, Integer> descriptor) {
		this.descriptor = descriptor;
	}

	public Map<Integer, Map<String, String>> getRecords() {
		return records;
	}

	public void setRecords(Map<Integer, Map<String, String>> records) {
		this.records = records;
	}

}
